package cn.com.sbell.vss.util;

import java.io.IOException;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;

import cn.com.sbell.vss.Util;
import cn.com.sbell.vss.VssConstants;
import cn.com.sbell.vss.monitor.PerformanceMonitor;
import cn.com.sbell.vss.csg.vsclient.util.CSGConfiguration;
import cn.com.sbell.vss.util.AlarmRaiser;
import cn.com.sbell.vss.csg.vsclient.util.AlarmDispatchGroup;
import cn.com.sbell.vss.util.HeartbeatSender;

public class CSGRegister {
	private final static Log log = LogFactory.getLog(CSGRegister.class);

	private HttpClient httpClient;

	private String cmsUrl;

	private String serverType;

	private String serverIp;

	private String deviceId;

	private volatile boolean running;

	private Thread registerThread;

	private long successRegisterInterval = 120000L;

	private long failRegisterInterval = 5000L;

	private static final int LIMITLESS_TIME = -1;

	private PerformanceMonitor csgPerformanceMonitor;
	
	private static final String NORMAL_ACTION="START";
	
	private AlarmRaiser alarmRaiser;

	private AlarmDispatchGroup alarmDisGroup;
	
	private HeartbeatSender hbs;
	
	public void init() {
		log.info("Init CSGRegister ...");
		running = true;
		new Thread() {
			public void run() {
				try {
					Thread.sleep(5000);
				} catch (InterruptedException ex) {
				}
				registerThread = new RegisterThread();
				registerThread.start();
				log
						.debug("A new CSGRegister Thread created: "
								+ registerThread);
			}
		}.start();

	}

	public void destroy() {
		log.info("Request to stop RegisterThread ...");
		running = false;
		if (registerThread != null) {
			registerThread.interrupt();
		}
	}

	public class RegisterThread extends Thread {

		public void run() {
			while (running) {
				// log.debug("Register Thread " + this + " started.");

				log.debug("CMS url is " + cmsUrl);

				PostMethod method = new PostMethod(cmsUrl + "/DeviceRegister");
				addHttpParameter(method, "deviceType", serverType);
				if (!Util.strIsNull(serverIp)) {
					addHttpParameter(method, "deviceIp", serverIp);
				}
				if (!Util.strIsNull(deviceId)) {
					addHttpParameter(method, "deviceId", deviceId);
				}
				log.debug("prepare to Register to CMS ");
				int statusCode = 0;
				RegisterResponse response = null;
				try {
					statusCode = httpClient.executeMethod(method);
					response = getResponse(method.getResponseBodyAsString());
				} catch (HttpException e) {
					log.warn("HTTP protocol violation: ", e);
				} catch (IOException e) {
					log.warn("Http transport error: ", e);
				} catch (Exception e) {
					log.warn("occur error", e);
				} finally {
					method.releaseConnection();
				}
				if (statusCode == HttpStatus.SC_OK
						&& VssConstants.CODE_SUCCESS.equals(response
								.getResultCode())) {
					csgPerformanceMonitor.setCpuHighThreshold(response
							.getCpuHighThreshold());
					csgPerformanceMonitor.setCpuLowThreshold(response
							.getCpuLowThreshold());
					csgPerformanceMonitor.setMemoryHighThreshold(response
							.getMemoryHighThreshold());
					csgPerformanceMonitor.setMemoryLowThreshold(response
							.getMemoryLowThreshold());
					csgPerformanceMonitor.setDiskHighThreshold(response
							.getDiskHighThreshold());
					csgPerformanceMonitor.setDiskLowThreshold(response
							.getDiskLowThreshold());
					csgPerformanceMonitor.setReportEnabled(response.isReportEnabled());
					csgPerformanceMonitor.setInterval(response.getInterval());
//					add vondart
					if((null!=response.getAsURL())&&CSGConfiguration.pattern.matcher(response.getAsURL()).matches()){
//					CSGConfiguration.AS_ALARM_URI=response.getAsURL();
					log.debug("CSGRegister changes as url to: "+response.getAsURL());
					alarmRaiser.setAlarmServerUrl(response.getAsURL());
					log.debug("AlarmRaiser changes as url to: "+response.getAsURL());
					alarmDisGroup.setAsURL(response.getAsURL());
					log.debug("AlarmDispatchGroup changes as url to: "+response.getAsURL());
					hbs.setAsUrl(response.getAsURL());
					log.debug("HeartBeat Sender changes as url to: "+response.getAsURL());
					}
					log.debug(csgPerformanceMonitor);
					
					
					if (response.getExpires() != null
							&& response.getExpires().intValue() == LIMITLESS_TIME) {
						log.debug("Method succcess: " + method.getStatusLine()
								+ "and response expires is "
								+ response.getExpires());
//						add vondart 
						running=false;
						
						break;
					}
					log.debug("Method succcess: " + method.getStatusLine()
							+ "but response expires is "
							+ response.getExpires() + " and start sleep "
							+ response.getExpires()+ " minute ");
					try {
						Thread
								.sleep(response.getExpires() == null ? successRegisterInterval
										: (long) response.getExpires()
												.intValue() * 60000);
					} catch (InterruptedException e) {
						log.warn("InterruptedException: " + e.getMessage());
					}

				} else {
					log.debug("statusCode is " + statusCode
							+ " and start sleep " + failRegisterInterval);
					try {
						Thread.sleep(failRegisterInterval);
					} catch (InterruptedException e) {
						log.warn("InterruptedException: " + e.getMessage());
					}
				}

			}
			log.debug("Register Thread " + this + " stopped.");
		}

		private void addHttpParameter(final PostMethod method, String name,
				String value) throws IllegalArgumentException {
			if (Util.strIsNull(value)) {
				return;
			}
			method.addParameter(name, value);
		}
	}

	public void setCmsUrl(String cmsUrl) {
		this.cmsUrl = cmsUrl;
	}

	public void setDeviceId(String deviceId) {
		this.deviceId = deviceId;
	}

	public void setHttpClient(HttpClient httpClient) {
		this.httpClient = httpClient;
	}

	public void setServerIp(String serverIp) {
		this.serverIp = serverIp;
	}

	public void setServerType(String serverType) {
		this.serverType = serverType;
	}

	public void setFailRegisterInterval(long failRegisterInterval) {
		this.failRegisterInterval = failRegisterInterval;
	}

	public void setSuccessRegisterInterval(long successRegisterInterval) {
		this.successRegisterInterval = successRegisterInterval;
	}

	public void setCsgPerformanceMonitor(
			PerformanceMonitor csgPerformanceMonitor) {
		this.csgPerformanceMonitor = csgPerformanceMonitor;
	}

	private RegisterResponse getResponse(String result) throws Exception {
		RegisterResponse response = new RegisterResponse();
		Document doc = DocumentHelper.parseText(result);
		String resultCode = getNodeText(doc, "//result/@code");
		response.setResultCode(resultCode);
		if (!VssConstants.CODE_SUCCESS.equals(resultCode)) {
			return response;
		}

		String expires = getNodeText(doc, "//expires");
		if (expires != null) {
			response.setExpires(new Integer(expires));
		}

//		response.setPassword(getNodeText(doc, "//password"));
//		response.setUsername(getNodeText(doc, "//username"));
		response.setCpuHighThreshold(Integer.parseInt(getNodeText(doc,
				"//cpu/highThreshold")));
		response.setCpuLowThreshold(Integer.parseInt(getNodeText(doc,
				"//cpu/lowThreshold")));
		response
				.setTimes(Integer.parseInt(getNodeText(doc, "//cpu/times")));
		response.setMemoryHighThreshold(Integer.parseInt(getNodeText(doc,
				"//memory/highThreshold")));
		response.setMemoryLowThreshold(Integer.parseInt(getNodeText(doc,
				"//memory/lowThreshold")));
		response.setDiskHighThreshold(new int[] { Integer.parseInt(getNodeText(
				doc, "//disk/highThreshold")) });
		response.setDiskLowThreshold(new int[] { Integer.parseInt(getNodeText(
				doc, "//disk/lowThreshold")) });
//		add vondart
		response.setDiskPath(new String[]{getNodeText(doc,"//disk/path")});
		String asNatIp=getNodeText(doc,"//as/natIp");
		String asNatPort=getNodeText(doc,"//as/natPort");
		String asIp=getNodeText(doc,"//as/ip");
		String asPort=getNodeText(doc,"//as/port");
		String asVapPath=getNodeText(doc,"//as/vapPath");
		String as=getNodeText(doc,"//as");
		String cms=getNodeText(doc,"//emsIp");
		
		if(null!=as){
			if(asVapPath.startsWith("/"))
			{
				asVapPath=asVapPath.substring(1);
			}
			if(cmsUrl.contains(cms))
			{
				response.setAsURL("http://"+asIp+":"+asPort+"/"+asVapPath);
			}else{
				response.setAsURL("http://"+asNatIp+":"+asNatPort+"/"+asVapPath);
			}
		}
		response.setInterval(Long.parseLong(getNodeText(doc,
				"//performanceSetting/interval"))*1000);
		String action=getNodeText(doc,"//performanceSetting/action");
		if(action!=null && NORMAL_ACTION.equals(action)){
			response.setReportEnabled(true);
		}		
		log.debug(response);
		return response;
	}

	private String getNodeText(Document doc, String path) {
		String message = null;
		Node node = doc.selectSingleNode(path);
		if (node != null) {
			message = node.getText();
		}
		return message;
	}

	public AlarmDispatchGroup getAlarmDisGroup() {
		return alarmDisGroup;
	}

	public void setAlarmDisGroup(AlarmDispatchGroup alarmDisGroup) {
		this.alarmDisGroup = alarmDisGroup;
	}

	public AlarmRaiser getAlarmRaiser() {
		return alarmRaiser;
	}

	public void setAlarmRaiser(AlarmRaiser alarmRaiser) {
		this.alarmRaiser = alarmRaiser;
	}

	public HeartbeatSender getHbs() {
		return hbs;
	}

	public void setHbs(HeartbeatSender hbs) {
		this.hbs = hbs;
	}

}
